/**
 * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}}
 */
{{#description}}
    {{#generateSwagger1Annotations}}
@ApiModel(description = "{{{description}}}")
    {{/generateSwagger1Annotations}}
    {{#generateSwagger2Annotations}}
@Schema({{#name}}name = "{{name}}", {{/name}}description = "{{{description}}}")
    {{/generateSwagger2Annotations}}
{{/description}}
{{#micronaut_serde_jackson}}
@io.micronaut.serde.annotation.Serdeable
{{/micronaut_serde_jackson}}
{{#jackson}}
@JsonPropertyOrder({
  {{#vars}}
  {{classname}}.JSON_PROPERTY_{{nameInSnakeCase}}{{^-last}},{{/-last}}
  {{/vars}}
})
@JsonTypeName("{{name}}")
{{/jackson}}
{{#additionalModelTypeAnnotations}}
{{{.}}}
{{/additionalModelTypeAnnotations}}
{{>common/generatedAnnotation}}{{#discriminator}}{{>common/model/typeInfoAnnotation}}{{/discriminator}}{{>common/model/xmlAnnotation}}{{#useBeanValidation}}
@Introspected
{{/useBeanValidation}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}{{!
Declare the class with extends and implements
}}public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{#-last}} {{/-last}}{{/vendorExtensions.x-implements}}{
    {{#serializableModel}}
    private static final long serialVersionUID = 1L;

    {{/serializableModel}}
    {{#vars}}
        {{#isEnum}}
            {{^isContainer}}
{{>common/model/modelInnerEnum}}
            {{/isContainer}}
            {{#isContainer}}
                {{#mostInnerItems}}
{{>common/model/modelInnerEnum}}
                {{/mostInnerItems}}
            {{/isContainer}}
        {{/isEnum}}
    public static final String JSON_PROPERTY_{{nameInSnakeCase}} = "{{baseName}}";
        {{#withXml}}
    @Xml{{#isXmlAttribute}}Attribute{{/isXmlAttribute}}{{^isXmlAttribute}}Element{{/isXmlAttribute}}(name = "{{items.xmlName}}{{^items.xmlName}}{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}{{/items.xmlName}}"{{#xmlNamespace}}, namespace = "{{.}}"{{/xmlNamespace}})
          {{#isXmlWrapped}}
    @XmlElementWrapper(name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}"{{#xmlNamespace}}, namespace = "{{.}}"{{/xmlNamespace}})
          {{/isXmlWrapped}}
        {{/withXml}}
        {{#vendorExtensions.x-field-extra-annotation}}
        {{{vendorExtensions.x-field-extra-annotation}}}
        {{/vendorExtensions.x-field-extra-annotation}}
        {{#vendorExtensions.x-is-jackson-optional-nullable}}
            {{#isContainer}}
    private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>undefined();
            {{/isContainer}}
            {{^isContainer}}
    private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
            {{/isContainer}}
        {{/vendorExtensions.x-is-jackson-optional-nullable}}
        {{^vendorExtensions.x-is-jackson-optional-nullable}}
            {{#isContainer}}
    private {{{datatypeWithEnum}}} {{name}}{{#required}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{/required}}{{^required}} = null{{/required}};
            {{/isContainer}}
            {{^isContainer}}
    {{#isDiscriminator}}protected{{/isDiscriminator}}{{^isDiscriminator}}private{{/isDiscriminator}} {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
            {{/isContainer}}
        {{/vendorExtensions.x-is-jackson-optional-nullable}}

    {{/vars}}
    {{#requiredPropertiesInConstructor}}
    public {{classname}}({{#requiredVars}}{{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}}{{/requiredVars}}) {
        {{#parent}}
        super({{#vendorExtensions.requiredParentVars}}{{name}}{{^-last}}, {{/-last}}{{/vendorExtensions.requiredParentVars}});
        {{/parent}}
        {{#vendorExtensions.requiredVars}}
        this.{{name}} = {{name}};
        {{/vendorExtensions.requiredVars}}
    }

    {{/requiredPropertiesInConstructor}}
    {{^requiredPropertiesInConstructor}}
    public {{classname}}() {
        {{#parent}}
        super();
        {{/parent}}
    }
    {{/requiredPropertiesInConstructor}}
    {{#vars}}
        {{^isReadOnly}}
    public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
            {{#vendorExtensions.x-is-jackson-optional-nullable}}
        this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
            {{/vendorExtensions.x-is-jackson-optional-nullable}}
            {{^vendorExtensions.x-is-jackson-optional-nullable}}
        this.{{name}} = {{name}};
            {{/vendorExtensions.x-is-jackson-optional-nullable}}
        return this;
    }

            {{#isArray}}
    public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
                {{#vendorExtensions.x-is-jackson-optional-nullable}}
        if (this.{{name}} == null || !this.{{name}}.isPresent()) {
            this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}});
        }
        try {
            this.{{name}}.get().add({{name}}Item);
        } catch (java.util.NoSuchElementException e) {
            // this can never happen, as we make sure above that the value is present
        }
        return this;
                {{/vendorExtensions.x-is-jackson-optional-nullable}}
                {{^vendorExtensions.x-is-jackson-optional-nullable}}
                    {{^required}}
        if (this.{{name}} == null) {
            this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
        }
                    {{/required}}
        this.{{name}}.add({{name}}Item);
        return this;
                {{/vendorExtensions.x-is-jackson-optional-nullable}}
    }

            {{/isArray}}
            {{#isMap}}
    public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
                {{#vendorExtensions.x-is-jackson-optional-nullable}}
        if (this.{{name}} == null || !this.{{name}}.isPresent()) {
            this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}});
        }
        try {
            this.{{name}}.get().put(key, {{name}}Item);
        } catch (java.util.NoSuchElementException e) {
            // this can never happen, as we make sure above that the value is present
        }
    return this;
                {{/vendorExtensions.x-is-jackson-optional-nullable}}
                {{^vendorExtensions.x-is-jackson-optional-nullable}}
                    {{^required}}
        if (this.{{name}} == null) {
            this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
        }
                    {{/required}}
        this.{{name}}.put(key, {{name}}Item);
        return this;
                {{/vendorExtensions.x-is-jackson-optional-nullable}}
  }

            {{/isMap}}
        {{/isReadOnly}}
    /**
        {{#description}}
     * {{description}}
        {{/description}}
        {{^description}}
     * Get {{name}}
        {{/description}}
        {{#minimum}}
     * minimum: {{minimum}}
        {{/minimum}}
        {{#maximum}}
     * maximum: {{maximum}}
        {{/maximum}}
     * @return {{name}}
     */
{{>common/model/beanValidation}}{{!
        }}{{#generateSwagger1Annotations}}
    @ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
        {{/generateSwagger1Annotations}}
        {{#generateSwagger2Annotations}}
    @Schema(name = "{{{baseName}}}"{{#isReadOnly}}, accessMode = Schema.AccessMode.READ_ONLY{{/isReadOnly}}{{#example}}, example = "{{{.}}}"{{/example}}{{#description}}, description = "{{{.}}}"{{/description}}, requiredMode = {{#required}}Schema.RequiredMode.REQUIRED{{/required}}{{^required}}Schema.RequiredMode.NOT_REQUIRED{{/required}})
        {{/generateSwagger2Annotations}}
        {{#vendorExtensions.x-extra-annotation}}
    {{{vendorExtensions.x-extra-annotation}}}
        {{/vendorExtensions.x-extra-annotation}}
        {{#vendorExtensions.x-is-jackson-optional-nullable}}
{{!unannotated, Jackson would pick this up automatically and add it *in addition* to the _JsonNullable getter field}}  @JsonIgnore
        {{/vendorExtensions.x-is-jackson-optional-nullable}}
        {{^vendorExtensions.x-is-jackson-optional-nullable}}
            {{#jackson}}
{{>common/model/jackson_annotations}}{{/jackson}}{{/vendorExtensions.x-is-jackson-optional-nullable}}    public {{#useOptional}}{{^required}}Optional<{{/required}}{{/useOptional}}{{{datatypeWithEnum}}}{{#useOptional}}{{^required}}>{{/required}}{{/useOptional}} {{getter}}() {
        {{#vendorExtensions.x-is-jackson-optional-nullable}}
            {{#isReadOnly}}
{{! A readonly attribute doesn't have setter => jackson will set null directly if explicitly returned by API, so make sure we have an empty JsonNullable}}    if ({{name}} == null) {
        {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
    }
    {{/isReadOnly}}
        return {{name}}.orElse(null);
        {{/vendorExtensions.x-is-jackson-optional-nullable}}
        {{^vendorExtensions.x-is-jackson-optional-nullable}}
          {{#useOptional}}
            {{#required}}
        return {{name}};
            {{/required}}
            {{^required}}
        return Optional.ofNullable({{name}});
            {{/required}}
          {{/useOptional}}
          {{^useOptional}}
        return {{name}};
          {{/useOptional}}
        {{/vendorExtensions.x-is-jackson-optional-nullable}}
    }

        {{#vendorExtensions.x-is-jackson-optional-nullable}}
{{>common/model/jackson_annotations}}
    public JsonNullable<{{{datatypeWithEnum}}}> {{getter}}_JsonNullable() {
        return {{name}};
    }

    @JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
    {{#isReadOnly}}private{{/isReadOnly}}{{^isReadOnly}}public{{/isReadOnly}} void {{setter}}_JsonNullable(JsonNullable<{{{datatypeWithEnum}}}> {{name}}) {
    {{! For getters/setters that have name differing from attribute name, we must include setter (albeit private) for jackson to be able to set the attribute}}       this.{{name}} = {{name}};
    }

        {{/vendorExtensions.x-is-jackson-optional-nullable}}
        {{^isReadOnly}}
            {{#jackson}}
                {{^vendorExtensions.x-is-jackson-optional-nullable}}
{{>common/model/jackson_annotations}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{#vendorExtensions.x-setter-extra-annotation}}       {{{vendorExtensions.x-setter-extra-annotation}}}
{{/vendorExtensions.x-setter-extra-annotation}}{{/jackson}}    public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
            {{#vendorExtensions.x-is-jackson-optional-nullable}}
        this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
            {{/vendorExtensions.x-is-jackson-optional-nullable}}
            {{^vendorExtensions.x-is-jackson-optional-nullable}}
        this.{{name}} = {{name}};
            {{/vendorExtensions.x-is-jackson-optional-nullable}}
    }

        {{/isReadOnly}}
    {{/vars}}
    @Override
    public boolean equals(Object o) {
    {{#useReflectionEqualsHashCode}}
        return EqualsBuilder.reflectionEquals(this, o, false, null, true);
    {{/useReflectionEqualsHashCode}}
    {{^useReflectionEqualsHashCode}}
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        {{#hasVars}}
        {{classname}} {{classVarName}} = ({{classname}}) o;
        return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} &&
            {{/-last}}{{/vars}}{{#parent}} &&
            super.equals(o){{/parent}};
        {{/hasVars}}
        {{^hasVars}}
        return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};
        {{/hasVars}}
    {{/useReflectionEqualsHashCode}}
    }

    @Override
    public int hashCode() {
    {{#useReflectionEqualsHashCode}}
        return HashCodeBuilder.reflectionHashCode(this);
    {{/useReflectionEqualsHashCode}}
    {{^useReflectionEqualsHashCode}}
        return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
    {{/useReflectionEqualsHashCode}}
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("class {{classname}} {\n");
        {{#parent}}
        sb.append("    ").append(toIndentedString(super.toString())).append("\n");
        {{/parent}}
        {{#vars}}
        sb.append("    {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n");
        {{/vars}}
        sb.append("}");
        return sb.toString();
    }

    /**
     * Convert the given object to string with each line indented by 4 spaces
     * (except the first line).
     */
    private{{#jsonb}} static{{/jsonb}} String toIndentedString(Object o) {
        if (o == null) {
            return "null";
        }
        return o.toString().replace("\n", "\n    ");
    }

    {{#parcelableModel}}
    public void writeToParcel(Parcel out, int flags) {
        {{#model}}
            {{#isArray}}
        out.writeList(this);
            {{/isArray}}
            {{^isArray}}
                {{#parent}}
        super.writeToParcel(out, flags);
                {{/parent}}
                {{#vars}}
        out.writeValue({{name}});
                {{/vars}}
            {{/isArray}}
        {{/model}}
    }

    {{classname}}(Parcel in) {
        {{#isArray}}
        in.readTypedList(this, {{arrayModelType}}.CREATOR);
        {{/isArray}}
        {{^isArray}}
            {{#parent}}
        super(in);
            {{/parent}}
            {{#vars}}
                {{#isPrimitiveType}}
        {{name}} = ({{{datatypeWithEnum}}})in.readValue(null);
                {{/isPrimitiveType}}
                {{^isPrimitiveType}}
        {{name}} = ({{{datatypeWithEnum}}})in.readValue({{complexType}}.class.getClassLoader());
                {{/isPrimitiveType}}
            {{/vars}}
        {{/isArray}}
    }

    public int describeContents() {
        return 0;
    }

    public static final Parcelable.Creator<{{classname}}> CREATOR = new Parcelable.Creator<{{classname}}>() {
        public {{classname}} createFromParcel(Parcel in) {
        {{#model}}
            {{#isArray}}
      {{classname}} result = new {{classname}}();
            result.addAll(in.readArrayList({{arrayModelType}}.class.getClassLoader()));
            return result;
            {{/isArray}}
            {{^isArray}}
            return new {{classname}}(in);
            {{/isArray}}
        {{/model}}
        }

        public {{classname}}[] newArray(int size) {
            return new {{classname}}[size];
        }
    };
    {{/parcelableModel}}
    {{#visitable}}
    {{#discriminator}}
    /**
     * Accept the visitor and invoke it for the specific {{classname}} type.
     *
     * @param visitor the {{classname}} visitor
     * @param <T> the return type of the visitor
     * @return the result from the visitor
     */
    public <T> T accept(Visitor<T> visitor) {
        return visitor.visit{{classname}}(this);
    }

    /**
     * A {{classname}} visitor implementation allows visiting the various {{classname}} types.
     *
     * @param <R> the return type of the visitor
     */
    public interface Visitor<R> {
        {{#discriminator.mappedModels}}
        R visit{{modelName}}({{modelName}} value);
        {{/discriminator.mappedModels}}
        R visit{{classname}}({{classname}} value);
    }

    {{/discriminator}}
    {{#parent}}
        {{#interfaces.0}}
    @Override
    public <T> T accept({{{parent}}}.Visitor<T> visitor) {
        return visitor.visit{{classname}}(this);
    }
        {{/interfaces.0}}
    {{/parent}}
    {{/visitable}}
}
